﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPFShapeDrawing
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Triangle SampleTriangle;
        Line SideA;
        Line SideB;
        Line SideC;
        TextBlock txt1;
        TextBlock txt2;
        TextBlock txt3;
        Path path1;
        Path path2;
        Path path3;

        public MainWindow()
        {

            InitializeComponent();
            // Add a Line Element

        }

        private void m_btnCalculate_Click(object sender, RoutedEventArgs e)
        {
            double[] angles = new double[3] { 0, 0, 0 };
            double[] sides = new double[3] { 0, 0, 0 };

            // Check if the sides and angles were defined or not
            if (m_tbAngle_alpha.Text != "")
            {
                if (!double.TryParse(m_tbAngle_alpha.Text, out angles[0]))
                    return;
            }

            if (m_tbAngle_beta.Text != "")
            {
                if (!double.TryParse(m_tbAngle_beta.Text, out angles[1]))
                    return;
            }

            if (m_tbAngle_gamma.Text != "")
            {
                if (!double.TryParse(m_tbAngle_gamma.Text, out angles[2]))
                    return;
            }

            if (m_tbSide_a.Text != "")
            {
                if (!double.TryParse(m_tbSide_a.Text, out sides[0]))
                    return;
            }

            if (m_tbSide_b.Text != "")
            {
                if (!double.TryParse(m_tbSide_b.Text, out sides[1]))
                    return;
            }

            if (m_tbSide_c.Text != "")
            {
                if (!double.TryParse(m_tbSide_c.Text, out sides[2]))
                    return;
            }

            // Create and solve the triangle
            SampleTriangle = new Triangle(angles, sides);
            try
            {
                Triangle answerTriangle = SampleTriangle.solve();

                // Clean old sides and measurements of the frame
                m_gridDrawing.Children.Remove(SideA);
                m_gridDrawing.Children.Remove(SideB);
                m_gridDrawing.Children.Remove(SideC);
                m_gridDrawing.Children.Remove(txt1);
                m_gridDrawing.Children.Remove(txt2);
                m_gridDrawing.Children.Remove(txt3);
                m_gridDrawing.Children.Remove(path1);
                m_gridDrawing.Children.Remove(path2);
                m_gridDrawing.Children.Remove(path3);

                // Create the sides' lines
                SideC = new Line();
                SideC.StrokeThickness = 2;
                SideC.Stroke = System.Windows.Media.Brushes.Black;
                SideB = new Line();
                SideB.StrokeThickness = 2;
                SideB.Stroke = System.Windows.Media.Brushes.Black;
                SideA = new Line();
                SideA.StrokeThickness = 2;
                SideA.Stroke = System.Windows.Media.Brushes.Black;

                double x1, x2, x3, y1, y2, y3;
                double[] tc = new double[6];

                // Generate the triangle with its respectives coordenates
                tc = generateTriangle(answerTriangle.Angles[0], answerTriangle.Angles[1], answerTriangle.Angles[2]);
                // Centralize the triangle placing the centroid in the center of the frame
                tc = centralizeCentroid(tc[0], tc[1], tc[2], tc[3], tc[4], tc[5]);

                x1 = tc[0];
                y1 = tc[1];
                x2 = tc[2];
                y2 = tc[3];
                x3 = tc[4];
                y3 = tc[5];

                // Define the position of the lines
                SideC.X1 = x1;
                SideC.Y1 = y1;
                SideC.X2 = x2;
                SideC.Y2 = y2;
                SideB.X1 = x2;
                SideB.Y1 = y2;
                SideB.X2 = x3;
                SideB.Y2 = y3;
                SideA.X1 = x3;
                SideA.Y1 = y3;
                SideA.X2 = x1;
                SideA.Y2 = y1;

                // Define the position of the measurements' texts
                double txt1x, txt1y, txt2x, txt2y, txt3x, txt3y;
                if (x1 > x2)
                {
                    txt1x = (x1 - 20 + x2 - 20) / 2;
                    txt1y = (y1 - 20 + y2 - 20) / 2;
                }
                else
                {
                    txt1x = (x1 - 20 + x2 - 20) / 2;
                    txt1y = (y1 + 10 + y2 + 10) / 2;
                }

                if (x3 > x1)
                {
                    txt3x = (x3 + 12 + x1 + 12) / 2;
                    txt3y = (y3 - 20 + y1 - 20) / 2;
                }
                else
                {
                    txt3x = (x3 + 12 + x1 + 12) / 2;
                    txt3y = (y3 + 10 + y1 + 10) / 2;
                }

                // Create the object for each measurement text
                txt1 = new TextBlock();
                txt1.Text = answerTriangle.Sides[2].ToString();
                txt1.FontSize = 14;
                txt1.FontWeight = FontWeights.Bold;
                txt1.FontFamily = new FontFamily("Century Gothic");
                txt1.RenderTransform = new TranslateTransform
                {
                    X = txt1x,
                    Y = txt1y
                };

                txt2 = new TextBlock();
                txt2.Text = answerTriangle.Sides[1].ToString();
                txt2.FontSize = 14;
                txt2.FontWeight = FontWeights.Bold;
                txt2.FontFamily = new FontFamily("Century Gothic");
                txt2.RenderTransform = new TranslateTransform
                {
                    X = (x2 + x3) / 2,
                    Y = (y2 + 11.8 + y3 + 11.8) / 2
                };

                txt3 = new TextBlock();
                txt3.Text = answerTriangle.Sides[0].ToString();
                txt3.FontSize = 14;
                txt3.FontWeight = FontWeights.Bold;
                txt3.FontFamily = new FontFamily("Century Gothic");
                txt3.RenderTransform = new TranslateTransform
                {
                    X = txt3x,
                    Y = txt3y
                };

                // Collect the smaller side
                int smaller = 0;
                for (int i = 1; i < 3; i++)
                {
                    if (answerTriangle.Sides[smaller] > answerTriangle.Sides[i])
                        smaller = i;
                }

                path1 = new Path();
                path2 = new Path();
                path3 = new Path();

                // Check if this side is greater than 20% of the average of the other two sides.
                // In order to decide if it is drawing or not the arcs.
                if (answerTriangle.Sides[smaller] > (0.2 * (answerTriangle.Sides[(smaller + 1) % 3] + answerTriangle.Sides[(smaller + 2) % 3])/2))
                {

                    path1 = DrawArc(new Point(x2, y2), 20, 0, answerTriangle.Angles[0]);
                    path2 = DrawArc(new Point(x1, y1), 20, -answerTriangle.Angles[2], -answerTriangle.Angles[2]-answerTriangle.Angles[1]);
                    path3 = DrawArc(new Point(x3, y3), 20, 180, 180-answerTriangle.Angles[2]);

                }

                // Define sides and angles in the labels
                Side0Label.Content = "Side 1: " + answerTriangle.Sides[0].ToString();
                Side1Label.Content = "Side 2: " + answerTriangle.Sides[1].ToString();
                Side2Label.Content = "Side 3: " + answerTriangle.Sides[2].ToString();
                Angle0Label.Content = "Opposite angle: " + answerTriangle.Angles[0].ToString();
                Angle1Label.Content = "Opposite angle: " + answerTriangle.Angles[1].ToString();
                Angle2Label.Content = "Opposite angle: " + answerTriangle.Angles[2].ToString();
                TotalAreaLabel.Content = "Total Area: " + (Math.Abs((answerTriangle.Sides[1] * answerTriangle.Sides[0] * Math.Sin(ToRadians(answerTriangle.Angles[2])) / 2)));

                // Draw the entire triangle
                m_gridDrawing.Children.Add(SideA);
                m_gridDrawing.Children.Add(SideB);
                m_gridDrawing.Children.Add(SideC);
                m_gridDrawing.Children.Add(txt1);
                m_gridDrawing.Children.Add(txt2);
                m_gridDrawing.Children.Add(txt3);
                m_gridDrawing.Children.Add(path1);
                m_gridDrawing.Children.Add(path2);
                m_gridDrawing.Children.Add(path3);
            }
            catch (InvalidOperationException exception)
            {
                //MessageBox.Show(exception.Message);
                ErrorLabel.Content = exception.Message;
                Side0Label.Content = "";
                Side1Label.Content = "";
                Side2Label.Content = "";
                Angle0Label.Content = "";
                Angle1Label.Content = "";
                Angle2Label.Content = "";
                TotalAreaLabel.Content = "";
                // Clean old sides and measurements of the frame
                m_gridDrawing.Children.Remove(SideA);
                m_gridDrawing.Children.Remove(SideB);
                m_gridDrawing.Children.Remove(SideC);
                m_gridDrawing.Children.Remove(txt1);
                m_gridDrawing.Children.Remove(txt2);
                m_gridDrawing.Children.Remove(txt3);
                m_gridDrawing.Children.Remove(path1);
                m_gridDrawing.Children.Remove(path2);
                m_gridDrawing.Children.Remove(path3);
            }

        }

        double ToRadians(double Angle)
        {
            return Angle * Math.PI / 180;
        }


        // This function will generate the coordenates of the triangle just using the 3 angles
        double[] generateTriangle(double anglealpha, double anglebeta, double anglegamma)
        {
            // Vector containing all the 6 coordinates of each vertex of the triangle
            double[] triangleCoordinates = new double[6];
            // Variables of the measurement of each side of the triangle
            double a, b, c;

            // These conditions will decide which side is the largest in order to set 250 in this same side
            // So, the triangle will never get out the frame

            // If the angle alpha is the largest, so side a is the largest side
            if (anglealpha >= anglebeta && anglealpha >= anglegamma)
            {
                a = 250;
                c = a * Math.Sin(ToRadians(anglegamma)) / Math.Sin(ToRadians(anglealpha));
            }
            // If the angle beta is the largest, so side b is the largest side
            else if (anglebeta >= anglealpha && anglebeta >= anglegamma)
            {
                b = 250;
                a = b * Math.Sin(ToRadians(anglealpha)) / Math.Sin(ToRadians(anglebeta));
                c = b * Math.Sin(ToRadians(anglegamma)) / Math.Sin(ToRadians(anglebeta));
            }
            // If the angle gamma is the largest, so side c is the largest side
            else
            {
                c = 250;
                a = c * Math.Sin(ToRadians(anglealpha)) / Math.Sin(ToRadians(anglegamma));
            }

            // Define the coordinates
            triangleCoordinates[0] = 0;
            triangleCoordinates[1] = 0;
            triangleCoordinates[2] = 0 - c * Math.Cos(ToRadians(anglealpha));
            triangleCoordinates[3] = 0 + c * Math.Sin(ToRadians(anglealpha));
            triangleCoordinates[4] = triangleCoordinates[1] + a * Math.Cos(ToRadians(anglegamma));
            triangleCoordinates[5] = triangleCoordinates[3];

            return triangleCoordinates;
        }

        // This function will centralize the triangle in the frame calculating its centroid and putting the triangle's centroid
        // in the center of the frame
        double[] centralizeCentroid(double x1, double y1, double x2, double y2, double x3, double y3)
        {
            // Vector containing all the 6 coordinates of each vertex of the triangle
            double[] triangleCoordinates = new double[6];
            // Variables used to calculate the difference comparing to the centroid
            double CentroidXfac;
            double CentroidYfac;

            // The center of the frame is seted as (200, 150)
            CentroidXfac = 200 - ((x1 + x2 + x3) / 3);
            CentroidYfac = 150 - ((y1 + y2 + y3) / 3);

            // Centralize the triangle in the frame
            triangleCoordinates[0] = x1 + CentroidXfac;
            triangleCoordinates[1] = y1 + CentroidYfac;
            triangleCoordinates[2] = x2 + CentroidXfac;
            triangleCoordinates[3] = y2 + CentroidYfac;
            triangleCoordinates[4] = x3 + CentroidXfac;
            triangleCoordinates[5] = y3 + CentroidYfac;

            return triangleCoordinates;
        }

        Path DrawArc(Point Center, double radius, double startAngleDegrees, double endAngleDegrees)
        {
            PathGeometry pathGeometry = new PathGeometry();
            PathFigure figure = new PathFigure();
            figure.StartPoint = new Point(Center.X + radius * Math.Cos(ToRadians(startAngleDegrees)),
                                          Center.Y - radius * Math.Sin(ToRadians(startAngleDegrees)));
            Point endPoint = new Point(Center.X + radius * Math.Cos(ToRadians(endAngleDegrees)),
                                       Center.Y - radius * Math.Sin(ToRadians(endAngleDegrees)));
            figure.Segments.Add(
            new ArcSegment(
                            endPoint,
                            new Size(radius, radius),
                            0,
                            ((endAngleDegrees - startAngleDegrees) > 180),
                            (startAngleDegrees < endAngleDegrees) ? SweepDirection.Counterclockwise : SweepDirection.Clockwise,
                            true
                          )
            );
            pathGeometry.Figures.Add(figure);
            Path path = new Path();
            path.Data = pathGeometry;
            //path.Fill = Brushes.Pink;
            path.Stroke = Brushes.Green;
            return path;
        }

    }
}